package com.chen.blue.service.system.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.chen.blue.annotation.permission.DataPermission;
import com.chen.blue.container.PermissionFlag;
import com.chen.blue.converter.system.DeptConverter;
import com.chen.blue.converter.system.UserConverter;
import com.chen.blue.dictionary.CommonDict;
import com.chen.blue.domain.delete.system.DataScopeUserDeptDelete;
import com.chen.blue.domain.delete.system.RoleDelete;
import com.chen.blue.domain.delete.system.UserDelete;
import com.chen.blue.domain.delete.system.UserRoleDelete;
import com.chen.blue.domain.dto.system.DataScopeUserDeptDto;
import com.chen.blue.domain.dto.system.UserDto;
import com.chen.blue.domain.dto.system.UserRoleDto;
import com.chen.blue.domain.dto.system.update.DataScopeUserDeptDtoEdit;
import com.chen.blue.domain.dto.system.update.UserDtoEdit;
import com.chen.blue.domain.dto.system.update.UserRoleDtoEdit;
import com.chen.blue.domain.model.system.DeptModel;
import com.chen.blue.domain.model.system.LoginUser;
import com.chen.blue.domain.model.system.UsersModel;
import com.chen.blue.domain.query.system.UserQuery;
import com.chen.blue.domain.vo.system.DeptVo;
import com.chen.blue.domain.vo.system.UserVo;
import com.chen.blue.exception.e.DtoNullException;
import com.chen.blue.mapper.system.UsersMapper;
import com.chen.blue.result.DataResult;
import com.chen.blue.result.R;
import com.chen.blue.service.candidate.CandidateInfoService;
import com.chen.blue.service.security.SecurityService;
import com.chen.blue.service.system.IDataScopeUserDeptService;
import com.chen.blue.service.system.IDeptService;
import com.chen.blue.service.system.IUserRoleService;
import com.chen.blue.service.system.IUsersService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.chen.blue.utils.PageInfoUtil;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.springframework.beans.BeanUtils;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 用户信息表 服务实现类
 * </p>
 *
 * @author CLT
 * @since 2024-04-27
 */
@SuppressWarnings("all")
@Service("userService")
public class IUsersServiceImpl extends ServiceImpl<UsersMapper, UsersModel> implements IUsersService {

    @Resource
    private IUserRoleService iUserRoleService;

    @Resource
    private IDataScopeUserDeptService iDataScopeUserDeptService;

    @Resource
    private IDeptService iDeptService;

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean addUser(UserDto userDto) throws DtoNullException {

        if (Objects.isNull(userDto)) {
            throw new DtoNullException("参数为空,不可添加");
        }

        // 账户不可重复
        vaildUserName(userDto.getUsername());

        UsersModel usersModel = converter(userDto);

        CandidateInfoService.setCreator(usersModel);

        boolean b1 = super.save(usersModel);
        // 用户角色
        boolean b2 = Objects.nonNull(userDto.getRoleIds()) ? iUserRoleService.addUserRole(buildUserRoleRelation(usersModel.getId(), userDto)) : false;
        // 用户部门权限ID
        boolean b3 = Objects.nonNull(userDto.getDeptIdArr()) ? iDataScopeUserDeptService.addDataScopeUserDept(buildUserDeptRelation(usersModel.getId(), userDto)) : false;

        return b1;

    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean deleteUser(UserDelete userDelete) throws DtoNullException {

        if (Objects.isNull(userDelete)) {
            throw new DtoNullException("条件为空，不可删除");
        }

        // 验证当前账户是否可以删除
        vaild(userDelete);

        boolean b1 = Objects.nonNull(userDelete.getIds()) && !userDelete.getIds().isEmpty() ? super.removeByIds(userDelete.getIds()) : super.removeById(userDelete.getId());
        boolean b2 = iUserRoleService.deleteUserRole(converterUserRole(userDelete));
        if (!b2) log.warn("删除用户角色失败");
        boolean b3 = iDataScopeUserDeptService.deleteDataScopeUserDept(converterUserDept(userDelete));
        if (!b3) log.warn("删除用户部门权限失败");

        return b1;

    }

    @Override
    public boolean updateUserById(UserDtoEdit userDtoEdit) throws DtoNullException {

        if (Objects.isNull(userDtoEdit)) {
            throw new DtoNullException("参数为空");
        }

        vaild(userDtoEdit);

        UsersModel usersModel = converterUserRole(userDtoEdit);

        CandidateInfoService.setUpdater(usersModel);

        boolean b1 = super.updateById(usersModel);
        boolean b2 = buildUserRoleRelation(usersModel.getId(), userDtoEdit) != null ? iUserRoleService.updateUserRole(buildUserRoleRelation(usersModel.getId(), userDtoEdit)) : false;
        if (!b2) log.warn("修改用户角色失败");

        boolean b3 = buildUserDeptRelation(usersModel.getId(), userDtoEdit) != null ? iDataScopeUserDeptService.updateDataScopeUserDept(buildUserDeptRelation(usersModel.getId(), userDtoEdit)) : false;
        if (!b3) log.warn("修改用户部门权限失败");

        return b1;

    }

    @DataPermission
    @Override
    public DataResult<List<UserVo>> queryUser(UserQuery userQuery) throws DtoNullException {

        if (Objects.isNull(userQuery)) {
            throw new DtoNullException("查询条件为空");
        }

        LambdaQueryWrapper<UsersModel> wrapper = new LambdaQueryWrapper<>();
        if (Objects.nonNull(userQuery.getPageNo()) && Objects.nonNull(userQuery.getPageSize())) {
            PageHelper.startPage(userQuery.getPageNo(), userQuery.getPageSize());
        }
        if (Objects.nonNull(userQuery.getUsername()) && StrUtil.isNotBlank(userQuery.getUsername())) {
            wrapper.like(UsersModel::getUsername, userQuery.getUsername());
        }
        wrapper.orderByDesc(UsersModel::getCreateTime);

        List<UsersModel> usersModelList = super.list(wrapper);
        PageInfo<UsersModel> pageInfo = new PageInfo<>(usersModelList);
        PageHelper.clearPage();

        PermissionFlag.set(false);

        /**
         * 数据处理：添加部门信息
         */
        List<UserVo> userVoList = UserConverter.modelToVoList(pageInfo.getList());
        List<DeptModel> temp = iDeptService.list();
        List<UserVo> data = Objects.nonNull(temp) && !temp.isEmpty() ? userVoList.stream().peek(var1 -> {
            for (DeptModel deptModel : temp) {
                if (var1.getDeptId().equals(deptModel.getId()))
                    var1.setDeptName(deptModel.getName());
            }
        }).collect(Collectors.toList()) : null;

        /**
         * 统一结果返回
         */
        DataResult<List<UserVo>> dataResult = new DataResult<>();
        dataResult.setData(data);
        PageInfoUtil.setPageInfo(dataResult, pageInfo);

        return dataResult;
    }

    @Override
    public DataResult<UserVo> queryUserById(Long id) throws DtoNullException {

        if (Objects.isNull(id)) {
            throw new DtoNullException("ID为空");
        }

        UsersModel usersModel = super.getById(id);

        DataResult<UserVo> dataResult = new DataResult<>();
        UserVo userVo = UserConverter.modelToVo(usersModel);

        buildData(userVo, id);

        dataResult.setData(userVo);

        return dataResult;
    }

    @Override
    public boolean hasUser(String username) {

        if (Objects.isNull(username) || StrUtil.isBlank(username)) {
            return false;
        }

        LambdaQueryWrapper<UsersModel> wrap = new LambdaQueryWrapper<>();
        wrap.eq(UsersModel::getUsername, username);
        UsersModel usersModel = super.getOne(wrap);

        // 用户存在（账号唯一）
        if (Objects.nonNull(usersModel)) {
            return true;
        }

        return false;

    }

    @Override
    public UsersModel getUserByUsername(String username) {

        if (Objects.isNull(username) || StrUtil.isBlank(username)) {
            return null;
        }

        LambdaQueryWrapper<UsersModel> wrap = new LambdaQueryWrapper<>();
        wrap.eq(UsersModel::getUsername, username);
        UsersModel usersModel = super.getOne(wrap);


        return usersModel;
    }

    @Override
    public DataResult<Map<String, Object>> getCurrentUserInfo() throws DtoNullException {

        Map<String, Object> data = new HashMap<>();

        buildDate(data);

        DataResult<Map<String, Object>> dataResult = new DataResult<>();
        dataResult.setData(data);

        return dataResult;
    }

    @Override
    public List<UsersModel> getUsersByDeptId(Set<Long> deptIds) {

        if (Objects.isNull(deptIds) || deptIds.isEmpty())
            return new ArrayList<>();

        LambdaQueryWrapper<UsersModel> wrapper = new LambdaQueryWrapper<>();
        wrapper.in(UsersModel::getDeptId, deptIds);
        return super.list(wrapper);

    }

    /**
     * 装配数据
     *
     * @param usersModel
     */
    protected void buildData(UserVo userVo, Long userId) throws DtoNullException {

        Object result = iUserRoleService.queryRoleIdById(userId).getResult();
        if (result instanceof Collection) {
            userVo.setRoleIds((List<Long>) result);
            JSONArray jsonArray = JSONUtil.parseArray(Objects.nonNull(userVo.getPostIds()) ? userVo.getPostIds() : new Long[]{});
            userVo.setPostIdArr(jsonArray.toList(Long.class));
        }

    }

    protected void buildDate(Map<String, Object> data) throws DtoNullException {

        LoginUser loginUser = SecurityService.currentUser();
        UsersModel sysUser = loginUser.getSysUser();

        DataResult<List<String>> var1 = iUserRoleService.queryRoleCodeById(sysUser.getId());
        List<String> var3 = var1.getResult();
        data.put("permissions", var3);

        DataResult<List<String>> var2 = iUserRoleService.queryRoleById(sysUser.getId());
        List<String> var4 = var2.getResult();
        data.put("roles", var4);

        UserVo userVo = UserConverter.modelToVo(sysUser);
        buildData(userVo, sysUser.getId());
        data.put("user", userVo);

        DeptVo deptVo = DeptConverter.modelToVo(iDeptService.getById(sysUser.getDeptId()));
        data.put("deptInfo", deptVo);

    }

    protected List<UserRoleDto> buildUserRoleRelation(Long userId, UserDto userDto) {

        if (Objects.isNull(userDto.getRoleIds())) {
            return null;
        }

        List<UserRoleDto> list = new ArrayList<>();
        List<Long> roleIds = userDto.getRoleIds();
        UserRoleDto temp = null;
        for (Long roleId : roleIds) {
            temp = new UserRoleDto();
            temp.setUserId(userId);
            temp.setRoleId(roleId);
            list.add(temp);
        }

        return list;

    }

    protected List<DataScopeUserDeptDto> buildUserDeptRelation(Long userId, UserDto userDto) {

        if (Objects.isNull(userDto.getDeptIdArr())) {
            return null;
        }

        List<DataScopeUserDeptDto> list = new ArrayList<>();
        List<Long> deptIdArr = userDto.getDeptIdArr();
        DataScopeUserDeptDto temp = null;
        for (Long deptId : deptIdArr) {
            temp = new DataScopeUserDeptDto();
            temp.setUserId(userId);
            temp.setDeptId(deptId);
            list.add(temp);
        }

        return list;

    }


    protected List<UserRoleDtoEdit> buildUserRoleRelation(Long userId, UserDtoEdit userDtoEdit) {

        if (Objects.isNull(userDtoEdit.getRoleIds()) || userDtoEdit.getRoleIds().isEmpty()) {
            return null;
        }

        List<UserRoleDtoEdit> list = new ArrayList<>();
        List<Long> roleIds = userDtoEdit.getRoleIds();
        UserRoleDtoEdit temp = null;
        for (Long roleId : roleIds) {
            temp = new UserRoleDtoEdit();
            temp.setUserId(userId);
            temp.setRoleId(roleId);
            list.add(temp);
        }

        return list;

    }

    protected List<DataScopeUserDeptDtoEdit> buildUserDeptRelation(Long userId, UserDtoEdit userDtoEdit) {

        if (Objects.isNull(userDtoEdit.getDeptIdArr()) || userDtoEdit.getDeptIdArr().isEmpty()) {
            return null;
        }

        List<DataScopeUserDeptDtoEdit> list = new ArrayList<>();
        List<Long> deptIdArr = userDtoEdit.getDeptIdArr();
        DataScopeUserDeptDtoEdit temp = null;
        for (Long deptId : deptIdArr) {
            temp = new DataScopeUserDeptDtoEdit();
            temp.setUserId(userId);
            temp.setDeptId(deptId);
            list.add(temp);
        }

        return list;

    }

    /**
     * 数据转换
     *
     * @param userDto
     * @return
     */
    protected UsersModel converter(UserDto userDto) {

        UsersModel usersModel = UserConverter.dtoToModel(userDto);
        usersModel.setPostIds(JSONUtil.toJsonStr(userDto.getPostIdArr()));

        // 密码加密
        BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
        String bcPassword = bCryptPasswordEncoder.encode(userDto.getPassword());
        usersModel.setPassword(bcPassword);

        return usersModel;

    }

    protected UsersModel converterUserRole(UserDtoEdit userDtoEdit) {

        UsersModel usersModel = UserConverter.dtoEditToModel(userDtoEdit);
        usersModel.setPostIds(Objects.nonNull(userDtoEdit.getPostIdArr()) ? JSONUtil.toJsonStr(userDtoEdit.getPostIdArr()) : null);

        return usersModel;

    }

    protected UserRoleDelete converterUserRole(UserDelete userDelete) {

        UserRoleDelete userRoleDelete = new UserRoleDelete();
        if (Objects.nonNull(userDelete.getIds())) {
            userRoleDelete.setUserIds(userDelete.getIds());
        } else if (Objects.nonNull(userDelete.getId())) {
            userRoleDelete.setUserId(userDelete.getId());
        }

        return userRoleDelete;

    }

    protected DataScopeUserDeptDelete converterUserDept(UserDelete userDelete) {

        DataScopeUserDeptDelete dataScopeUserDeptDelete = new DataScopeUserDeptDelete();
        if (Objects.nonNull(userDelete.getIds())) {
            dataScopeUserDeptDelete.setUserIds(userDelete.getIds());
        } else if (Objects.nonNull(userDelete.getId())) {
            dataScopeUserDeptDelete.setUserId(userDelete.getId());
        }

        return dataScopeUserDeptDelete;

    }


    protected void vaildUserName(String username) throws DtoNullException {

        List<String> usernames = super.list().stream().map(UsersModel::getUsername).collect(Collectors.toList());
        if (usernames.contains(username)) {
            throw new DtoNullException("账号重复");
        }

    }


    /**
     * 系统账户不可操作
     *
     * @param condition
     * @throws DtoNullException
     */
    protected void vaild(Object condition) throws DtoNullException {

        if (condition instanceof UserDtoEdit) {

            UserDtoEdit userDtoEdit = (UserDtoEdit) condition;
            UsersModel usersModel = super.getById(userDtoEdit.getId());
            if (CommonDict.SYSTEM_ADMIN.equals(usersModel.getUsername())) {
                throw new DtoNullException("系统账号不可操作");
            }

        } else if (condition instanceof UserDelete) {
            UserDelete userDelete = (UserDelete) condition;
            if (Objects.nonNull(userDelete.getId())) {
                UsersModel usersModel = super.getById(userDelete.getId());
                if (CommonDict.SYSTEM_ADMIN.equals(Objects.nonNull(usersModel) ? usersModel.getUsername() : "")) {
                    throw new DtoNullException("系统账号不可操作");
                }
            } else {
                List<String> usernames = super.listByIds(userDelete.getIds()).stream().map(UsersModel::getUsername).collect(Collectors.toList());
                if (usernames.contains(CommonDict.SYSTEM_ADMIN)) {
                    throw new DtoNullException("系统账号不可操作");
                }
            }
        }

    }

}
